WealthGrowthRedistribution Simulation Analysis

Simulation studies

Code
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.2     ✔ tibble    3.3.0
✔ lubridate 1.9.4     ✔ tidyr     1.3.1
✔ purrr     1.1.0     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Code
library(marquee) # For using markdown in ggplots
library(arrow) # For reading parquet data

Attaching package: 'arrow'

The following object is masked from 'package:lubridate':

    duration

The following object is masked from 'package:utils':

    timestamp
Code
library(glue)

# Hand-picked rescale parameters
## Low tax regime fitting
scale_down_low_wealthgains = 7.75
scale_down_low_realizedwealthgains1_5 = 19
## High tax regime fitting
scale_down_high_wealthgains = 5.5
shift_high_wealthgains = -0.005
scale_down_high_realizedwealthgains1_5 = 10
shift_high_realizedwealthgains1_5 = -0.01

# Compute a few more variables
wrangle <- function(d) d |> 
  mutate(Ns = format(N, scientific = FALSE, big.mark = ","), # renaming for plots
         `Tax Regime` = case_when(
          tax_regime == "wealth" ~ "Wealth Tax", 
          tax_regime == "wealth gains" ~ "Wealth Gains Tax", 
          tax_regime == "realized wealth gains" ~ "Realized Wealth Gains Tax"), # renaming for plots
         taxrate_wealth_scaled_1 = case_when(
          tax_regime == "wealth" ~ taxrate,
          tax_regime == "wealth gains" ~ taxrate/scale_down_low_wealthgains,
          tax_regime == "realized wealth gains" ~ taxrate/scale_down_low_realizedwealthgains1_5),
         taxrate_wealth_scaled_2 = case_when(
          tax_regime == "wealth" ~ taxrate,
          tax_regime == "wealth gains" ~ taxrate/scale_down_high_wealthgains + shift_high_wealthgains,
          tax_regime == "realized wealth gains" ~ taxrate/scale_down_high_realizedwealthgains1_5 + shift_high_realizedwealthgains1_5),
         across(starts_with("tailexp"), \(x) x - 1)) 
d1 <- read_parquet("simdata_v1/WealthGrowthRedistribution_StrippedDown experiments v1 all.parquet") |> wrangle()
d2 <- read_parquet("simdata_v2/WealthGrowthRedistribution_StrippedDown experiments v2 all.parquet") |> wrangle()|> 
 mutate(`Tax Regime` = 
         if_else(tax_regime == "realized wealth gains", paste0(`Tax Regime`, " (", realization_scale, ")"), `Tax Regime`))

We did two simulation studies with two different versions of the model. Both simulations are comparable. The model used in the first version is identical in behavior with the second model for specific parameter values. The second model is an extension of the first one. The newer model includes a third tax regime called “Realized Wealth Gains Tax (1.5)” and also included the specification of an allowance threshold specified by a fraction of the median of the taxbase at the current time step.

The implementation of the taxation now first specifies the tax base for each individual and then applies proportional taxation to this tax base potentially taking into account an allowance as a fraction of the median value1 of the tax base.2 In that way, the allowance can be specified in identically for all three tax regimes.

The three tax regime differ in the computation of the tax base:

Tax regime Tax base
Wealth Tax Current wealth of the individual. It mimicks the typical wealth tax.
Wealth Gains Tax The difference between the new pre-tax wealth after the random growth of wealth and the wealth before but only if this difference is positive. So, only wealth gains in the last time step are taxed. It mimicks a simple form of capital income tax as only income (new wealth) from capital (old wealth) is taxed.
Realized Wealth Gains Tax (1.5) This regime builds on the wealth gains tax and is inspired by the fact that for stocks or company ownership capital income is only taxed when it is realized by selling shares for cash. This implies that randomly increasing wealth can remain untaxed for longer times. Our behavioral assumption is individuals realize wealth gains when the value is 1.5 times larger than wealth at the acquisition.3 Further on, we assume that after realization the money is immediately invested again in new shares making the wealth after realization and taxation (and the regular redistribution) the new wealth on acquisition where future wealth gains are compared to.

Model behavior examples

First we show same examples of the model behavior as visualized in our exploratory NetLogo model.4 In all simulations all individuals are initialized with a wealth of one. Then we typically run 200 time steps of random multiplicative wealth changes for each individual plus taxation (based on the given tax regime) and redistribution of the total wealth revenue in equal shares to all individuals. As taxation in the real world is typically year-wise this can be compared to a history of 200 years. Sometimes we study the longer period of 1,000 time steps.

We first show trajectories without taxation and then demonstrate the different tax regimes and finally different allowances for the wealth tax regime.

In every simulations the random multiplicative growth factors come from a log-normal distribution with parameters \(\mu = 0.02\) and \(\sigma = 0.3\).

The screenshots of the NetLogo interfaces below show several output measures many off them tracked over time.

Output measures in NetLogo’s interface
output measures explanation notes
wealth distribution At each time step the inverse cumulative distribution of wealth is plotted as a log-log-plot. A tail exponent (slope of the downward line in the log-log plot) is fitted for the top 10% percent of the wealth distribution (can be adjusted using quantile_fit). The fitted tail exponent is tracked over time. Shows that a distribution converges towards a traveling wave of stable shape. Constant speed in the log-log-plot reflects exponential growth. Stabilization of the fitted tail exponent indicates a stabilization of the shape.
mean wealth Tracks the mean wealth over time. The long term growth rate is \(\exp (\frac{\log \bar{w}}{t})\) where \(\bar{w}\) is the current mean wealth. The long term growth rate is the average factor needed to for exponential growth from the initial value one to the current wealth over \(t\) time steps.
taxshare Taxshare is the total tax revenue divided by the total wealth. It quantifies the level of redistribution. The fraction paying tax is the fraction of individuals which have positive tax in the current round. The taxshare is a good indicator to compare what tax rates lead to similar outcomes under different tax regimes and tax allowances.
log changes The log change in one time step is the difference between the log of the mean wealth and the log of the mean wealth the time step before. The log change distribution is the distribution of all log changes over time. Tracks the fluctuation of the mean wealth.
volatility The standard deviation of the last 25 (or 10 or 50) log changes Volatility clustering maybe noticed.
wealth inequality (Gini) Gini coefficient of the current wealth distribution. Stabilization of the Gini coefficient is another indicator of a stable shape of the distribution.
wealth shares The fraction of wealth of the Top 10%, the Top 1%, or just the wealthiest individual. Easier to understand inequality indicators.
immobility Tracks the fraction of individuals in the Bottom 50% (50%-90% Range, Top 10%, and Top 1%) which were in the same group 10 (or 25 or 50) time steps before. The larger these numbers the less social mobility happens.

No taxation

We show two simulation without taxation one with 1,000 individuals and one with 10,000. We show a snapshot after 200 time steps and another one of the same run after 1,000 time steps.

The trajectories show the phenomenon of lossy multiplicative stochastic processes. With no taxation we are studying an ensemble of \(N\) independent processes of multiplicative stochastic growth. In the long run, every single process converges to a long term yearly growth factor of \(\exp (\mu - \frac{\sigma^2}{2}) \approx 0.975\). However, the expected value of the yearly growth factor is \(\exp \mu \approx 1.0202\). Empirically, this can be approached using large ensembles. However, in every ensemble each individual process tends to shrink over time while dispersion between trajectories is constantly growing. This implies that the mean wealth (as the total wealth) relies more and more on one individual only. This is clearly visible in the long trajectories and in particular in the smaller ensemble (\(N=1000, t=1000\)) where the mean wealth has shrunk from one to 0.114 over the 1,000 time steps while the Gini index has quickly converged to almost one (most unequal distribution). Further on some extreme spike of the mean wealth are visible. These are time steps where the wealthiest individual had a lucky streak which is reflected in the “wealth shares” graph which shows that in these times the riches individual has also almost 100% of the total wealth. The distribution of wealth converges to a log-normal distribution with an every increasing standard deviation due to the central limit theorem. This reflected in a parabola shape of the right tail of the inverse cumulative distribution function in a log-log-plot. The increasing standard deviation of the distribution also prevents that the power law tail exponent fit does not stabilize but tends to lower and lower values.

Tax regimes

The redistribution of the total tax revenue in equal shares to all individuals adds an additive component to the individual multiplicative stochastic wealth growth processes. This implies that the wealth distribution converges to a distribution with a power law tail and an exponent stabilizing over time. Further on, the whole shape of the distribution stabilze to a traveling wave, that means that distribution in the log-log-plot only shifts with constant speed along the x-axis.

The simulations of the three different tax regimes always run for 200 time steps with 10,000 individuals. For each regime we use a different tax rate such that all three simulations lead to roughly comparable output measures for the tax share (tax revue fraction at total wealth), inequality, and immobility.

This shows that similar level output measures can be reached with very different tax rates under the different tax regimes.

Tax rate 1.5%

Tax rate 11%

Tax rate 22%

Tax allowance

The simulations of the tax allowance also always run for 200 time steps with 10,000 individuals. We focus on the wealth tax regime and show three runs for a tax of 1.5% (as above) with no allowance (as seen before), with an allowance identical to the median wealth and an allowance of ten times the median wealth. Finally, we show one additional run with the large allowance but with a tax rate raised to 3% such that output measures for output measures for the tax share (tax revue fraction at total wealth), inequality, and immobility are comparable to no allowance.

Wealth tax with tax rate 1.5%

Wealth tax with tax rate 1.5%

Wealth tax with tax rate 1.5%

Wealth tax with tax rate 3%

Data Analysis

Different populations

The fitted tail exponents after 200 time steps show a clear linear trend on average above a certain tax rate (different for different tax regime) as show cased for simulations with \(N = 10,000\) individuals.

Code
d1 |> filter(N == 10000, stop_tick == 200) |>
 ggplot(aes(taxrate, tailexp_top10_stop_tick)) +
 geom_point(alpha = 0.05) +
 geom_smooth(method = "gam", formula = y ~ s(x, bs = "cs")) +
 facet_grid(Ns ~ `Tax Regime`, scales = "free_x") +
 labs(x = "tax rate", y = "Fitted tail exponent (Top 10%)", 
      caption = paste(nrow(d1 |> filter(N==10000, taxrate==0.05, tax_regime=="wealth", stop_tick==200)),"simulation runs per tax rate")) +
 theme_minimal()

Fitted tail exponents

Based on this observation we look at the average tail exponent next for different values of \(N\).

Code
d1 |> summarize(mean_tailexp_top10_stop_tick = mean(tailexp_top10_stop_tick), 
               .by = c(`Tax Regime`, taxrate, Ns)) |> 
 ggplot(aes(taxrate, mean_tailexp_top10_stop_tick, color = Ns)) + 
 geom_line() +
 facet_wrap(~`Tax Regime`, scales = "free_x") +
 labs(x = "tax rate", y = "Average fitted tail exponent (Top 10%)", 
      caption = paste(nrow(d1 |> filter(N==10000, taxrate==0.05, tax_regime=="wealth", stop_tick==200)),"simulation runs per tax rate for N=1,000 and N=10,000; 100 runs for the other N")) +
 theme_minimal()

Average fitted tail exponents

Average tail exponents are almost identical leading us to the observation that the population has no major effect on the stabilization of the travel wave distribution.

We look at other outcome measures in the same way.

Code
d1 |> summarize(`Mean Gini` = mean(gini_stop_tick),
                `Mean Share Top 1%` = mean(share_top1_stop_tick), 
                `Mean Immobility Top 10%` = mean(stillintop10_past_tick_3),
                `Mean Volatility` = mean(volatility_past_tick_2),
               .by = c(`Tax Regime`, taxrate, Ns)) |> 
 pivot_longer(c(`Mean Gini`, `Mean Share Top 1%`, `Mean Immobility Top 10%`, `Mean Volatility`)) |>
 rename(N = Ns) |> 
 ggplot(aes(taxrate, value, color = N)) + 
 geom_line() +
 facet_wrap(`Tax Regime` ~ name, scales = "free", ncol = 4) +
 labs(x = "tax rate", y = "Average value",
      caption = paste(nrow(d1 |> filter(N==10000, taxrate==0.05, tax_regime=="wealth", stop_tick==200)),"simulation runs per tax rate for N=1,000 and N=10,000; 100 runs for the other N")) +
 guides(color = guide_legend(position = "bottom", nrow = 1)) +
 theme_minimal() 

Average fitted tail exponents

For the the mean Gini coefficient and the mean immobility of the top 10% we find also almost no effect of population size. For the wealth share of the top 1% we find marginally larger values for larger populations for intermediate tax rates. Only for volatility we find a sizably higher values for smaller populations.

Over all, we see a stable patterns that inequality, immobility and volatility decreases with larger tax rates.

Long term growth rates

Code
d1 |> filter(N == 10000, stop_tick == 200) |>
 ggplot(aes(taxrate, growth_rate_all)) +
 geom_point(alpha = 0.05) +
 geom_smooth(method = "gam", formula = y ~ s(x, bs = "cs")) +
 facet_grid(Ns ~ `Tax Regime`, scales = "free_x") +
 labs(x = "tax rate", y = "Long term growth rates", 
      caption = paste(nrow(d1 |> filter(N==10000, taxrate==0.05, tax_regime=="wealth", stop_tick==200)),"simulation runs per tax rate")) +
 theme_minimal()

Long term growth rates
Code
d1 |> summarize(mean_growth_rate = mean(growth_rate_all), 
               .by = c(`Tax Regime`, taxrate, Ns)) |>
 rename(N = Ns) |> 
 ggplot(aes(taxrate, mean_growth_rate, color = N)) + 
 geom_line() +
 facet_wrap(~`Tax Regime`, scales = "free_x") +
 labs(x = "tax rate", y = "Average long term growth rates", 
      caption = "") +
 theme_minimal()

Average long term growth rates

Scaling tax rates to match different tax regimes

Scaling Fit 1

We hand-fitted two scaling factors such that outcome measures for different tax regimes coincide for different tax rates. To that end, we scaled down the tax rates of Wealth Gains Tax by a factor of 7.75 and those of Realized Wealth Gains (1.5) by a factor of 19.

Code
d2 |> filter(N == 10000, stop_tick == 200, allowance_fraction_median == 0) |> 
 summarize(`Mean Tail Exponent 10%` = mean(tailexp_top10_stop_tick), 
           `Mean Tail Exponent 1%` = mean(tailexp_top1_stop_tick), 
           `Mean Gini` = mean(gini_stop_tick), 
           `Mean Share Top 1%` = mean(share_top1_stop_tick), 
           `Mean Immobility Top 10%` = mean(stillintop10_past_tick_3),
           `Mean Share Top 10%` = mean(share_top10_stop_tick), 
           `Mean Immobility Bottom 50%` = mean(stillinbottom50_past_tick_3),
           `Mean taxshare` = mean(taxshare_stop_tick),
           .by = c(`Tax Regime`, taxrate_wealth_scaled_1, Ns)) |> 
 pivot_longer(c(`Mean Tail Exponent 10%`, `Mean Tail Exponent 1%`, `Mean Gini`, 
                `Mean Share Top 1%`, `Mean Share Top 10%`, 
                `Mean Immobility Top 10%`, `Mean Immobility Bottom 50%`, 
                `Mean taxshare`)) |>
 rename(N = Ns) |> 
 ggplot(aes(taxrate_wealth_scaled_1, value, color = `Tax Regime`)) + 
 geom_line() +
 facet_wrap(~name, scales = "free_y") +
 labs(x = "tax rate scaled by tax regimes") +
 labs(caption = glue('scales: Wealth Tax as is, Wealth Gains tax scaled down by {scale_down_low_wealthgains}\nRealized Wealth Gains (1.5) scaled down by {scale_down_low_realizedwealthgains1_5}')) +
 guides(color = guide_legend(position = "bottom", nrow = 1)) +
 theme_minimal()

Comparison of tax regimes with scales tax rates, version 1

For all the indicators the lines with rescaled tax rates coincide very well for low tax rates up to the Wealth Tax rate of 0.01. For Mean immobility the rescaled tax rates match fairly well for all tax rates.

For the critical value of Wealth Tax = 0.01 this implies critical values of Wealth Gains Tax = 0.0775 and Realized Wealth Gains Tax (1.5) = 0.19.

For the value of Wealth Tax = 0.015 this implies comparable values of Wealth Gains Tax = 0.11625 and Realized Wealth Gains Tax (1.5) = 0.285.

Scaling Fit 2

The next goal is to make output measures comparable for the larger taxrates in the linear tail exponent regime, which also coincides roughly with the regime were stochastic loss of growth potential is essentially eliminated.

The second handfitted rescaling involves scaling down and shifting backward.

Wealth Gains Tax rate: scale down by 5.5 and then shift by -0.005 (or first shift the original tax rates by -0.0275).

Realized Wealth Gains Tax (1.5) rate: scale down by 10 and then shift by -0.01 (or first shift the original tax rates by -0.1).

For the critical value of Wealth Tax = 0.01 this implies critical values of Wealth Gains Tax = 0.0825 and Realized Wealth Gains Tax (1.5) = 0.2.

Code
d2 |> filter(N == 10000, stop_tick == 200, allowance_fraction_median == 0) |> 
 summarize(`Mean Tail Exponent 10%` = mean(tailexp_top10_stop_tick), 
           `Mean Tail Exponent 1%` = mean(tailexp_top1_stop_tick), 
           `Mean Gini` = mean(gini_stop_tick), 
           `Mean Share Top 1%` = mean(share_top1_stop_tick), 
           `Mean Immobility Top 10%` = mean(stillintop10_past_tick_3),
           `Mean Share Top 10%` = mean(share_top10_stop_tick), 
           `Mean Immobility Bottom 50%` = mean(stillinbottom50_past_tick_3),
           `Mean taxshare` = mean(taxshare_stop_tick),
           .by = c(`Tax Regime`, taxrate_wealth_scaled_2, Ns)) |> 
 pivot_longer(c(`Mean Tail Exponent 10%`, `Mean Tail Exponent 1%`, `Mean Gini`, 
                `Mean Share Top 1%`, `Mean Share Top 10%`, 
                `Mean Immobility Top 10%`, `Mean Immobility Bottom 50%`, 
                `Mean taxshare`)) |>
 rename(N = Ns) |> 
 ggplot(aes(taxrate_wealth_scaled_2, value, color = `Tax Regime`)) + 
 geom_line() +
 facet_wrap(~name, scales = "free_y") +
 labs(x = "tax rate scaled by tax regimes") +
 labs(caption = glue('scales: Wealth Tax as is, Wealth Gains tax scaled down by {scale_down_high_wealthgains} and then shifted by {shift_high_wealthgains}\nRealized Wealth Gains (1.5) scaled down by {scale_down_high_realizedwealthgains1_5} and then shifted by {shift_high_realizedwealthgains1_5}')) +
 guides(color = guide_legend(position = "bottom", nrow = 1)) +
 theme_minimal()

Comparison of tax regimes with scales tax rates, version 2

For the value of Wealth Tax = 0.015 this implies comparable values of Wealth Gains Tax = 0.11 and Realized Wealth Gains Tax (1.5) = 0.25.

Taxshare vs. other measures

Code
# fig-cap: Comparison of tax regimes with scales tax rates, version 1
d2 |> filter(N == 10000, stop_tick == 200, allowance_fraction_median == 0) |>
 #count(tax_regime, allowance_fraction_median, realization_scale)
 rename(`Tail Exponent 10%` = tailexp_top10_stop_tick, 
        `Tail Exponent 1%` = tailexp_top1_stop_tick, 
        Gini =gini_stop_tick, 
        `Share Top 1%` = share_top1_stop_tick, 
        `Share Top 10%` = share_top10_stop_tick, 
        `Immobility Top 10%` = stillintop10_past_tick_3,
        `Immobility Bottom 50%` = stillinbottom50_past_tick_3,
        `Long-term Realized Growth Rate` = growth_rate_all,  
        Taxshare = taxshare_stop_tick,
        Taxrate = taxrate) |> 
 pivot_longer(c(`Tail Exponent 10%`, `Tail Exponent 1%`, `Gini`, `Share Top 1%`, `Share Top 10%`, 
                `Immobility Top 10%`,`Immobility Bottom 50%`,`Long-term Realized Growth Rate`,Taxrate)) |>
# rename(N = Ns) |> 
 ggplot(aes(Taxshare, value, color = `Tax Regime`)) + 
 geom_point(alpha = 0.05) +
 geom_smooth(method = 'gam', formula = y ~ s(x, bs = "cs"), xseq = seq(0,0.028,0.001),) +
 facet_wrap(~name, scales = "free_y") +
 labs(x = "Taxshare") +
 guides(color = guide_legend(position = "bottom", nrow = 1)) +
 theme_minimal()

Code
# fig-cap: #Comparison of tax regimes with scales tax rates, version 1
d2 |> filter(N == 10000, stop_tick == 200, allowance_fraction_median == 0) |> 
 rename(`Tail Exponent 10%` = tailexp_top10_stop_tick, 
        `Tail Exponent 1%` = tailexp_top1_stop_tick, 
        Gini =gini_stop_tick, 
        `Share Top 1%` = share_top1_stop_tick, 
        `Share Top 10%` = share_top10_stop_tick, 
        `Immobility Top 10%` = stillintop10_past_tick_3,
        `Immobility Bottom 50%` = stillinbottom50_past_tick_3,
        `Long-term Realized Growth Rate` = growth_rate_all,  
        Taxshare = taxshare_stop_tick,
        Taxrate = taxrate) |> 
 pivot_longer(c(`Tail Exponent 10%`, `Tail Exponent 1%`, `Gini`, `Share Top 1%`, `Share Top 10%`, 
                `Immobility Top 10%`,`Immobility Bottom 50%`,`Long-term Realized Growth Rate`,Taxrate)) |>
 ggplot(aes(Taxshare, value, color = `Tax Regime`)) + 
# geom_point(alpha = 0.05) +
 geom_smooth(method = 'gam', formula = y ~ s(x, bs = "cs"), xseq = seq(0,0.028,0.001),) +
 facet_wrap(~name, scales = "free_y") +
 labs(x = "Taxshare") +
 guides(color = guide_legend(position = "bottom", nrow = 2)) +
 theme_minimal()

Code
# fig-cap: #Comparison of tax regimes with scales tax rates, version 1
d2_taxshare <- d2 |> filter(N == 10000, stop_tick == 200, allowance_fraction_median == 0) |> 
 rename(`Tail Exponent 10%` = tailexp_top10_stop_tick, 
        `Tail Exponent 1%` = tailexp_top1_stop_tick, 
        Gini =gini_stop_tick, 
        `Share Top 1%` = share_top1_stop_tick, 
        `Share Top 10%` = share_top10_stop_tick, 
        `Immobility Top 10%` = stillintop10_past_tick_3,
        `Immobility Bottom 50%` = stillinbottom50_past_tick_3,
        `Long-term Realized Growth Rate` = growth_rate_all,  
        Taxshare = taxshare_stop_tick,
        Taxrate = taxrate) |> 
 pivot_longer(c(`Tail Exponent 10%`, `Tail Exponent 1%`, `Gini`, `Share Top 1%`, `Share Top 10%`, 
                `Immobility Top 10%`,`Immobility Bottom 50%`,`Long-term Realized Growth Rate`,Taxrate)) |>
 mutate(Taxshare_rounded = round(Taxshare, digits = 3)) |>
 #mutate(Taxshare_rounded = 2*round(Taxshare/2, digits = 3)) |>
 summarize(median = median(value),mean = mean(value), n = n(), sd = sd(value), q1=quantile(value, 0.25), q3=quantile(value,0.75),
           stderr = sd/sqrt(n), .by = c(name, Taxshare_rounded, `Tax Regime`)) 
d2_taxshare |> filter(Taxshare_rounded <= 0.03, `Tax Regime` %in% c("Wealth Tax", "Wealth Gains Tax", "Realized Wealth Gains Tax (1.5)")) |> 
 ggplot(aes(Taxshare_rounded, median, color = `Tax Regime`)) + 
# geom_point(alpha = 0.05) +
# geom_smooth(method = 'gam', formula = y ~ s(x, bs = "cs"), xseq = seq(0,0.028,0.001),) +
 geom_line() +
 geom_point() +
 geom_errorbar(aes(ymin = q1, ymax = q3), width = 0.0005) +
 # geom_errorbar(aes(ymin = mean - sd, ymax = mean + sd), width = 0.0005) +
 #xlim(c(0,0.025)) +
 facet_wrap(~name, scales = "free_y") +
 labs(x = "Taxshare (rounded)") +
 guides(color = guide_legend(position = "bottom", nrow = 2)) +
 theme_minimal()

Tax allowances

Focusing on the Wealth Tax only.

Code
# fig-cap: #Comparison of tax regimes with scales tax rates, version 1
d2 |> filter(N == 10000, stop_tick == 200, tax_regime == "wealth") |> 
 summarize(`Mean Tail Exponent` = mean(tailexp_top10_stop_tick), 
           `Mean Gini` = mean(gini_stop_tick), 
           `Mean Share Top 1%` = mean(share_top1_stop_tick), 
           `Mean Immobility Top 10%` = mean(stillintop10_past_tick_3),
           `Mean taxshare` = mean(taxshare_stop_tick),
           .by = c(allowance_fraction_median, taxrate_wealth_scaled_1, Ns)) |> 
 pivot_longer(c(`Mean taxshare`,`Mean Tail Exponent`, `Mean Gini`, `Mean Share Top 1%`, 
                `Mean Immobility Top 10%`)) |>
 rename(N = Ns) |> 
 mutate(`Allowance as fraction median` = factor(allowance_fraction_median)) |> 
 ggplot(aes(taxrate_wealth_scaled_1, value, color = `Allowance as fraction median`)) + 
 geom_line() +
 facet_wrap(~name, scales = "free_y") +
 labs(x = "tax rate") +
 guides(color = guide_legend(position = "bottom", nrow = 1)) +
 theme_minimal()

Now but tax revenue share.

Code
# fig-cap: #Comparison of tax regimes with scales tax rates, version 1
d2 |> filter(N == 10000, stop_tick == 200, tax_regime == "wealth") |> 
 rename(`Tail Exponent 10%` = tailexp_top10_stop_tick, 
        `Tail Exponent 1%` = tailexp_top1_stop_tick, 
        Gini =gini_stop_tick, 
        `Share Top 1%` = share_top1_stop_tick, 
        `Share Top 10%` = share_top10_stop_tick, 
        `Immobility Top 10%` = stillintop10_past_tick_3,
        `Immobility Bottom 50%` = stillinbottom50_past_tick_3,
        `Long-term Realized Growth Rate` = growth_rate_all,  
        Taxshare = taxshare_stop_tick,
        Taxrate = taxrate) |> 
 pivot_longer(c(`Tail Exponent 10%`, `Tail Exponent 1%`, `Gini`, `Share Top 1%`, `Share Top 10%`, 
                `Immobility Top 10%`,`Immobility Bottom 50%`, `Long-term Realized Growth Rate`, Taxrate)) |>
 #rename(N = Ns) |> 
 mutate(`Allowance as fraction median` = factor(allowance_fraction_median)) |> 
 ggplot(aes(Taxshare, value, color = `Allowance as fraction median`)) + 
 geom_point(alpha=0.05) +
 geom_smooth(method = 'gam', formula = y ~ s(x, bs = "cs"), xseq = seq(0,0.028,0.001),) +
 facet_wrap(~name, scales = "free_y") +
 guides(color = guide_legend(position = "bottom", nrow = 1)) +
 theme_minimal()

Insight for tax policy design for economic growth

For the design of taxation policy for prosperous (i.e., growing) economies, checking best-practice cases is of interest, because purely theoretical economic models may be too limited to work out in the real world. A problem with best-practice examples from the real world is, however, that it is hard to derive clear causal relationships about which parts of policies are instrumental for prosperity.

Our model insight adds to that question in two ways: First, loss of growth potential in finite populations or (in turn) growth increase triggered by wealth taxation and redistribution is an underappreciated effect of taxation and redistribution of wealth. Second, focusing on best practice examples by looking at empirical cases of economic growth in limited time-scales (including also 200 years here) may create a selection bias for cases of no or low wealth taxation in which growth is just triggered by lucky streaks of very wealthy people, while the overall average expectation is negative in the long run. Such selection biases may happen in every best-case selection; however, our simulations show that the effects of chance can be extreme and longer-lasting than in “normal cases” because of cumulative effects and the multiplicative nature of wealth increase.

On the first point: The model shows that the loss of growth potential can be eliminated by wealth taxation and redistribution. This is a strong argument for wealth taxation, which is often seen as an obstacle to economic growth. The model also shows that the level of taxation does not have to be very high to achieve this effect. Further on, the model shows that wealth taxation and redistribution naturally lead to a more stable and equitable distribution of wealth which may be conducive to economic growth, given the empirical evidence that many countries with high levels of wealth taxation tend to have economic growth and that wealthiest countries have typically not the most unequal wealth distributions.

On the second point: Focussing on simulation runs with the largest growth rates in a limited time period will create a selection bias towards cases with no or low wealth taxation. Extrapolating this to the real world may lead to the wrong conclusion that wealth taxation is detrimental to economic growth, because the most growing countries have no wealth taxation neglecting the possibility that this is driven by a few lucky streaks of the super rich. Anyway, causal reasoning based on selection of best cases is flawed whenever randomness is subject to play a non-negligible role on the measure selection is based on. The better way would be to select by input parameters like wealth tax regimes and tax rates and then study the output measures.

Footnotes

  1. That means, for a value of allowance_fraction_median = 1 only the amount above the median of the taxbase is taxed which implies that exactly half of the individuals pay taxes. For allowance_fraction_median = 10 only value above ten times the median taxbase is taxed which implies that much less the half of the population are paying taxes.↩︎

  2. More realistic would be to use allowance thresholds not being computed on the spot. However, for the sake of simplicity and comparability between different tax regimes and taxrates we refrained from modeling other methods of adjusting the allowance threshold with respect to the current wealth distribution.↩︎

  3. We introduce the parameter realization_scale = 1.5 here. It can be changed but we did not systematically study it yet.↩︎

  4. The model can be tested in NetLogoWeb however it runs much slower than in the desktop version and simulation runs tend to slow down while running. In NetLogoWeb N should be no more than 1,000. The NetLogo desktop version 6.4 is recommended for anything more than a first look. The model can can be downloaded from NetLogoWeb and then run locally.↩︎